﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VirtualPedal;
using System.Diagnostics;
using System.ComponentModel;

namespace VPApp
{
	/// <summary>
	/// Interaction logic for WaveView.xaml
	/// </summary>
	public partial class WaveView : UserControl
	{
		WriteableBitmap m_Bmp;
		float m_RangeInSeconds = 0.01f;
		float m_CurrentSample;
		float m_StartSample;
		float[] m_DataSamples;
		AudioPort m_Port;
		byte[] m_TempArray;
		Int64 m_CurrentWriteCursor = 0;

		public float MagFactor { get; set; }

		public WaveView()
		{
			InitializeComponent();
			MagFactor = 1.0f;
		}

		public void BindPort(AudioPort port)
		{
			UnBindPort();
			m_Port = port;
			m_TempArray = new byte[10 * port.Descriptor.SampleFrequency * port.Descriptor.BitsPerSample / 8];
			m_DataSamples = new float[10 * port.Descriptor.SampleFrequency];
			m_CurrentWriteCursor = 0;
		}

		public void UnBindPort()
		{
			m_Port = null;
			m_TempArray = null;
			m_DataSamples = null;
			m_CurrentWriteCursor = 0;
		}

		public void Render()
		{
			if (m_Bmp == null)
			{
				image1_SizeChanged(this, null);
			}

			m_Bmp.Clear(Colors.Black);

			if (m_Port == null)
				return;

			Int32 bytesRead = m_Port.DataBuffer.ReadAll(m_TempArray);
			Int32 bytesPerSample = (m_Port.Descriptor.BitsPerSample / 8);
			Int32 elapsedSamples = bytesRead / bytesPerSample;

			if(m_Port.Descriptor.BitsPerSample == 8)
			{
				for(int i=0; i<elapsedSamples; i++)
				{
					m_DataSamples[m_CurrentWriteCursor % m_DataSamples.Length] = m_TempArray[i] / 255.0f;
					m_CurrentWriteCursor++;
				}
			}
			else if(m_Port.Descriptor.BitsPerSample == 16)
			{
				for(int i=0; i<elapsedSamples; i++)
				{
					m_DataSamples[m_CurrentWriteCursor % m_DataSamples.Length] = BitConverter.ToInt16(m_TempArray, i * bytesPerSample) / (float)Int16.MaxValue;
					m_CurrentWriteCursor++;
				}
			}
			else if(m_Port.Descriptor.BitsPerSample == 32)
			{
				for(int i=0; i<elapsedSamples; i++)
				{
					m_DataSamples[m_CurrentWriteCursor % m_DataSamples.Length] = BitConverter.ToSingle(m_TempArray, i * bytesPerSample);
					m_CurrentWriteCursor++;
				}
			}

			m_CurrentSample = m_CurrentWriteCursor % m_DataSamples.Length;
			m_StartSample = m_CurrentSample - m_RangeInSeconds * m_Port.Descriptor.SampleFrequency;

			int NUM_DRAW_SAMPLES = 640;

			int lastY, currentY;
			lastY = SampleToPixel(0);

			float step = 1.0f / NUM_DRAW_SAMPLES;
			float pixStep = step * (float)m_Bmp.Width;
			float x = (float)m_Bmp.Width;

			for (float i = step; i < 1.0f; i+=step)
			{
				currentY = SampleToPixel(i);
				m_Bmp.DrawLine((int)(x + pixStep), lastY, (int)x, currentY, Colors.LightGreen);
				lastY = currentY;
				x -= pixStep;
			}
		}

		int SampleToPixel(float sampLoc)
		{
			float numSamplesBackward = sampLoc * (m_CurrentSample - m_StartSample);
			int sampleIndex = (int)Math.Round(m_CurrentSample - numSamplesBackward);
			sampleIndex = sampleIndex % m_DataSamples.Length;
			if (sampleIndex < 0)
				sampleIndex += m_DataSamples.Length;
			return (int)(m_Bmp.Height * (m_DataSamples[sampleIndex] * MagFactor + 1.0f) * 0.5f);
		}

		private void image1_SizeChanged(object sender, SizeChangedEventArgs e)
		{
			m_Bmp = BitmapFactory.New(Math.Max(256, (int)image1.ActualWidth), Math.Max(256, (int)image1.ActualHeight));
			m_Bmp.Clear(Colors.Black);
			image1.Source = m_Bmp;
		}
	}
}